package com.xianguo.datacenter.download.Thread;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.google.gson.Gson;
import com.xianguo.datacenter.domain.Response20;
import com.xianguo.datacenter.domain.SetDataBean;
import com.xianguo.datacenter.util.HttpUtils;
import com.xianguo.datacenter.util.UnitSwitch;

public class DownloadBaidDuYunThread extends Download implements Runnable {
    // 定义一些全局变量
    private static String cookie = null;
    private static boolean isDownload = true;//标记是否需要下载文件，false就只获取地址
    private static String server_filename = null;
    private static String size = null;
    private static final String getvcodeURL = "https://pan.baidu.com/api/getvcode?prod=pan";// 请求vcode地址，不变
    private int downloadSize = 0;
    private int lastdownloadSize = 0;
    private static boolean isReading = true;//是否在读流，更新进度
    private static long startTime = 0 ;
    private static long endTime = 0 ;
    private String webPath;//项目路径
    private String vCode;//需要的验证码
    private String vCodeState;//验证码状态  1需要验证码  2不需要验证码
    private String vCodePath;//验证码地址
    private int isstart;//下载速率计算器
    
    public DownloadBaidDuYunThread (){
    	downloadState = DownloadState.DOWNLOADING;//默认为正在下载
    }
    
	@Override
	public void run() {
		UID = UUID.randomUUID().toString();
        // 第一次获取cookie（）
		cookie = null;
        Map<String, String> map1 = HttpUtils.get(url, cookie);
        System.out.println("服务器返回的cookie：\n" + map1.get("cookie") + "\n");
        cookie = "PANWEB=1;" + map1.get("cookie").split(";")[0];// 抓包看到携带了PANWEB1，不设置也没问题
        List<Map<String, String>> params = getBodyParams(map1.get("body"));
        
        server_filename = params.get(0).get("server_filename");
        this.fileName = server_filename;
        size = params.get(0).get("size");
        this.maxProgres = Integer.parseInt(size);
        
        // 拼接post的url地址
        String post_url = getPostUrl(params);

        // 拼接post携带的参数
        Map<String, String> data = getPostData(params);

        // 发送post请求
        String responseJson = HttpUtils.post(post_url, data, cookie);
        System.out.println(responseJson + "\n");

        Gson gson = new Gson();
        Response20 response20 = gson.fromJson(responseJson, Response20.class);
        String errorCode = response20.getErrno();

        int count = 0;
        while (!errorCode.equals("0")) {
            count++;
            if (errorCode.equals("-20")) {
                // 下载超过3次，需要验证码,获取vcode和img地址
            	this.vCode = "";
                Map<String, String> generateValidateCode = generateValidateCode(count);
                if(generateValidateCode == null){
                    DownloadUtil.removeDownloadThread(UID);//验证码超时移除掉自己
                	System.out.println("验证码超时！");
                	return;
                }
                data.put("vcode_input", generateValidateCode.get("vcode_input"));
                data.put("vcode_str", generateValidateCode.get("vcode_str"));
                String responseJsonCode = HttpUtils.post(post_url, data, cookie);
                System.out.println(responseJsonCode + "\n");

                errorCode = gson.fromJson(responseJsonCode, Response20.class).getErrno();
                if (errorCode.equals("0")) {
                	response20 = gson.fromJson(responseJsonCode, Response20.class);
                }
                DownloadUtil.vcodeState = "1";
            }
        }
        
        vCodeState = "2";
 
        if (errorCode.equals("0")) {// 成功返回真实的url
            //String realURL = parseRealDownloadURL(responseJson);
            //System.out.println("成功！真实的下载链接为：" + realURL);
            if (isDownload) {
            	for(int i = 0;i<response20.getList().length;i++){
            		DownloadUtil.addHttpDownload(path, response20.getList()[i].getServer_filename(), response20.getList()[i].getDlink(),cookie);
            	}
            }else{
                System.out.println("配置不下载");
            }
        } else {
            System.out.println("尝试了" + count + "次，地址获取失败");
        }
        DownloadUtil.removeDownloadThread(UID);//百度云线程的作用已经完成了，去除掉自己。
	}
	
	 /**
     * POST请求的url地址
     */
    public static String getPostUrl(List<Map<String, String>> params) {
        /**
         * post请求（抓包可看到） 抓包看到logid，实际测试logid不携带也可以正常抓取
         * https://pan.baidu.com/api/
         * sharedownload?sign=2d970c761500085deb09d423d549dea2f4ef28da
         * &timestamp=
         * 1515400310&bdstoken=null&channel=chunlei&clienttype=0&web=1
         * &app_id=250528&logid=MTUxNTQwMDQ1NTc1MTAuOTYwMTE4NzIyMzcxMzYwNQ==
         */
        StringBuffer sb1 = new StringBuffer();
        sb1.append("https://pan.baidu.com/api/sharedownload?");
        sb1.append("sign=" + params.get(0).get("sign"));
        sb1.append("&timestamp=" + params.get(0).get("timestamp"));
        sb1.append("&bdstoken=" + params.get(0).get("bdstoken"));
        sb1.append("&channel=chunlei");
        sb1.append("&clienttype=0");
        sb1.append("&web=1");
        sb1.append("&app_id=" + params.get(0).get("app_id"));
        String post_url = sb1.toString();
        System.out.println("POST请求的网址：" + post_url);

        return post_url;
    }

    /**
     * 获取POST请求携带的参数
     */
    public static Map<String, String> getPostData(List<Map<String, String>> params) {
        // POST携带的参数(抓包可看到)
        Map<String, String> data = new HashMap<String, String>();
        data.put("encrypt", "0");
        data.put("product", "share");
        data.put("uk", params.get(0).get("uk"));
        data.put("primaryid", params.get(0).get("primaryid"));
        // 添加了[]，解码就是%5B %5D
        String fidlist="%5B";
        for(int i = 0; i < params.size(); i++){
        	if(i==0){
        		fidlist+=params.get(i).get("fid_list");
        	}else{
        		fidlist+=","+params.get(i).get("fid_list");
        	}
        }
        fidlist+="%5D";
        data.put("fid_list", fidlist);
        data.put("path_list", "");// 可以不写
        return data;
    }

    /**
     * 从post返回数据解析出dlink字段，真实的下载地址，这个地址有效期8h
     */
    public static String parseRealDownloadURL(String responseJson) {
        String realURL = "";
        Pattern pattern = Pattern.compile("\"dlink\":.*?,");
        Matcher matcher = pattern.matcher(responseJson);
        if (matcher.find()) {
            String tmp = matcher.group(0);
            String dlink = tmp.substring(9, tmp.length() - 2);
            realURL = dlink.replaceAll("\\\\", "");
        }
        return realURL;
    }

    /**
     * 获取并输入验证码
     * 
     * @return map{vcode_str:请求的vcode值, vcode_input:输入的验证码}
     */
    public Map<String, String> generateValidateCode(int count) {
        // 下载超过3次，需要验证码,获取vcode和img地址
        Map<String, String> vcodeResponse = HttpUtils.get(getvcodeURL, cookie);
        String res = vcodeResponse.get("body");
        System.out.println("获取vcode：" + vcodeResponse.get("body"));

        Gson gsonVcode = new Gson();
        Response20 responseVcode = gsonVcode.fromJson(res, Response20.class);
        String vcode = responseVcode.getVcode();
        String imgURL = responseVcode.getImg();
        System.out.println("vcode值：" + vcode);
        System.out.println("验证码地址：" + imgURL);

        // 请求验证码
        //Map<String, String> vCodeMap = HttpUtils.saveImage(webPath,imgURL, cookie);
        //vCodePath = vCodeMap.get("imgPath");
        vCodePath = imgURL; 
        vCodeState = "1";
        
        System.out.print("查看图片，输入验证码(第" + count + "次尝试/共5次):");
        Map<String, String> map = new HashMap<String, String>();
        try {
        	int SleepCount = 0;
        	while(true){
        		Thread.sleep(1000);
        		if(this.vCode != null && !"".equals(this.vCode))
        			break;
        		if(SleepCount >= 35){
        			return null;
        		}
        		SleepCount++;
        	}
            System.out.println("输入的验证码为：" + vCode + "\n");
            map.put("vcode_str", vcode);
            map.put("vcode_input", vCode);
        } catch (InterruptedException e) {
			System.out.println("获取验证码错误！");
		}

        return map;
    }

    /**
     * 正则匹配出json字符串，将json字符串转化为java对象。
     */
    public static List<Map<String, String>> getBodyParams(String body) {
    	List<Map<String,String>> maps = new ArrayList<Map<String,String>>();

        String setData = "";
        Pattern pattern_setData = Pattern.compile("setData.*?;");
        Matcher matcher_setData = pattern_setData.matcher(body);
        if (matcher_setData.find()) {
            String tmp = matcher_setData.group(0);
            setData = tmp.substring(8, tmp.length() - 2);
            // System.out.println("setData:" + setData + "\n");

            Gson gson = new Gson();
            SetDataBean bean = gson.fromJson(setData, SetDataBean.class);
            
            for(int i = 0;i<bean.getFile_list().getList().length ;i++){
            	System.out.println("==========================新建百度云文件==========================");
            	System.out.println("sign--" + bean.getSign());
            	System.out.println("token--" + bean.getBdstoken());
            	System.out.println("timestamp--" + bean.getTimestamp());
            	System.out.println("uk--" + bean.getUk());
            	System.out.println("shareid--" + bean.getShareid());
            	System.out.println("fs_id--" + bean.getFile_list().getList()[i].getFs_id());
            	System.out.println("file_name--" + bean.getFile_list().getList()[i].getServer_filename());
            	System.out.println("size--" + bean.getFile_list().getList()[i].getSize());
            	System.out.println("app_id--" + bean.getFile_list().getList()[i].getApp_id() + "\n");
            }
            Map<String, String> map;
            for(int i = 0;i<bean.getFile_list().getList().length ;i++){
            	map = new HashMap<String, String>();
            	map.put("sign", bean.getSign());
            	map.put("timestamp", bean.getTimestamp());
            	map.put("bdstoken", bean.getBdstoken());
            	map.put("app_id", bean.getFile_list().getList()[i].getApp_id());
            	map.put("uk", bean.getUk());
            	map.put("shareid", bean.getShareid());
            	map.put("primaryid", bean.getShareid());
            	map.put("fs_id", bean.getFile_list().getList()[i].getFs_id());
            	map.put("fid_list", bean.getFile_list().getList()[i].getFs_id());
            	map.put("server_filename", bean.getFile_list().getList()[i].getServer_filename());
            	map.put("size", bean.getFile_list().getList()[i].getSize());
            	maps.add(map);
            }
        }

        return maps;
    }
    
    //下载百度云文件
    public Map<String, String> download(String url, String cookie, String filename, final String totalSize) {
        InputStream in = null;
        FileOutputStream fos = null;
        Map<String, String> map = new HashMap<String, String>();
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection connection = realUrl.openConnection();
            // 设置通用的请求属性
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            connection.setConnectTimeout(10000);
//          connection.setReadTimeout(5000);
            if (null != cookie) {
                connection.setRequestProperty("Cookie", cookie);
            }
            // 建立实际的连接
            connection.connect();

            in = connection.getInputStream();
            File file = new File(path+"\\\\"+filename);
            if (!file.getParentFile().exists())
                file.getParentFile().mkdir();
            if (file.exists())
                file.delete();
            file.createNewFile();
            fos = new FileOutputStream(file);
            

            System.out.println("保存文件名称：" + filename);
            System.out.println("文件总大小：" + totalSize);
            //利用字符数组读取流数据

            startTime = System.currentTimeMillis();
            isstart = 0;
            speed();
            isReading = true;
            int len;
            byte[] arr = new byte[1024 * 8];
            while((len = in.read(arr)) != -1) {
                fos.write(arr, 0, len);
                downloadSize += len;
                progres = downloadSize;
            }

            endTime = System.currentTimeMillis();
            String speed = UnitSwitch.calculateSpeed(downloadSize, endTime-startTime);
            String total1 = UnitSwitch.formatSize(Long.parseLong(totalSize));
            System.out.println(UnitSwitch.formatSize(downloadSize) + "/" + total1 + "，平均下载速率：" + speed);
            System.out.println("下载完成，总耗时：" + (endTime - startTime)/1000 + "秒");
            isstart = 1;
            DownloadUtil.removeDownloadThread(this.UID);
            return map;
        } catch (Exception e) {
            System.err.println(e.getMessage());
        } finally {
            isReading = false;
            try {
                if (in != null) {
                    in.close();
                }
                if(fos != null){
                    fos.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return null;
    }
    
    //下载速率
    public void speed() {
		if(isstart==1)
			return;
		Timer timer = new Timer(); 
		timer.schedule(new TimerTask() {
		public void run() {      
			speed=downloadSize-lastdownloadSize;
			lastdownloadSize=progres;
			speed();
		}    
		}, 1000);// 指定延迟1000毫秒后执行  
	}

	public String getWebPath() {
		return webPath;
	}

	public void setWebPath(String webPath) {
		this.webPath = webPath;
	}

	public String getvCode() {
		return vCode;
	}

	public void setvCode(String vCode) {
		this.vCode = vCode;
	}

	public String getvCodeState() {
		return vCodeState;
	}

	public void setvCodeState(String vCodeState) {
		this.vCodeState = vCodeState;
	}

	public String getvCodePath() {
		return vCodePath;
	}

	public void setvCodePath(String vCodePath) {
		this.vCodePath = vCodePath;
	}

}
